require 'google/api_client'
#require 'zip/zip'
require 'csv'

class RecordsController < ApplicationController
before_filter :build_data

  def build_data
    @client = Google::APIClient.new
    @client.authorization.client_id = '271044387937.apps.googleusercontent.com'
    @client.authorization.client_secret = 'tYKfWGyoYC8uqN7041VC4Fpg'
    @client.authorization.scope = 'https://www.googleapis.com/auth/calendar'
    @client.authorization.redirect_uri = 'http://localhost:3000/oauth2callback'

#    @client.authorization.access_token = 'ya29.AHES6ZQQYGsGdxZDa0EJUrq2G-d-HfcoWp9DeCYVQ1hk0Vk'

#    @client.authorization.approval_prompt = 'auto'
#    qvs = @client.authorization.authorization_uri.query_values
    #SET approval_prompt to auto
#    qvs["approval_prompt"] = "auto"
#    @client.authorization.authorization_uri.query_values = qvs
    
    @client.authorization.code = params[:code] if params[:code]
#        logger.debug session.inspect
    if session[:token_id]
      # Load the access token here if it's available
      token_pair = TokenPair.find(session[:token_id])
      @client.authorization.update_token!(token_pair.to_hash)
    else
      if TokenPair.first
        token_pair = TokenPair.first        
        @client.authorization.update_token!(token_pair.to_hash)
      end
    end
    if @client.authorization.refresh_token && @client.authorization.expired?
      @client.authorization.fetch_access_token!
    end
    @calendar = @client.discovered_api('calendar', 'v3')
    unless @client.authorization.access_token || request.path_info =~ /^\/oauth2/
#      redirect_to 'http://localhost:3000/oauth2authorize'
      return redirect_to @client.authorization.authorization_uri(:approval_prompt => :auto).to_s, :status => 303
    end


    # GET RECORD DATA
    @tMax = params[:timeMax].nil? ? Time.now.to_datetime.to_s : params[:timeMax].to_datetime.to_s
    @tMin = params[:timeMin].nil? ? Time.now.to_datetime.beginning_of_month.to_s : params[:timeMin].to_datetime.to_s

    calendars = @client.execute(:api_method => @calendar.calendar_list.list)    
    #, :parameters => {'showHidden' => 'True'}
    calendars = calendars.data
    @events = []

    calendars.items.each do |cal|
      if not cal.summary.nil? and cal.summary.downcase.include?(".ketimesheet")
        @events.concat(@client.execute(:api_method => @calendar.events.list, :parameters => {'calendarId' => cal.id, 'timeMax' => @tMax, 'timeMin' => @tMin}).data.items)
      end
    end
    #clean up record list!
    Record.destroy_all
    Notice.destroy_all
    #create records for each event
    @events.each do |e|
      j = e.summary.nil? ? nil : Job.where('lower(name) = ?', e.summary.downcase).first
      if j.nil?
        #raise email error  
        body = 'Event: #{e.htmlLink}<br/> used the Title: #{j}.  This can not be matched to our current list of Projects:<br/><ul>'
        Job.all.each do |jo|
          body += '<li>#{jo.name}</li'
        end
        body += '</ul>'
        # Send Consolidated Email 
        Notice.new(:email => e.creator.email, :subject => 'TimeSheet Watcher: Warning - Project Not Defined', :body => body, :event_json => e.to_json).save
        #e.summary.nil? ? ErrorMailer.job_not_defined_warning(e.creator.email, "<blank>") : ErrorMailer.job_not_defined_warning(e.creator.email, e.summary.downcase).deliver      
        j = Job.where(:name => 'UNMAPPED').first
      end
      if not e.description.nil?
        breaks = calc_breaks(e.description)
        if breaks < 0
          #raise email error
          body = 'Negative time entered for Break value in Event: #{e.htmlLink}<br/>Breaks value parsed from value in description: #{e.description}<br/>This value has been made positive for you.'
          # Send Consolidated Email
          Notice.new(:email => e.creator.email, :subject => 'TimeSheet Watcher: Warning - Negative Break Value', :body => body, :event_json => e.to_json).save
#          ErrorMailer.negative_break_time(e.creator.email, breaks).deliver      
          breaks = -1 * breaks
        end
      else
        breaks = 0
      end
      @record = Record.new(:calendar_id => e.id, :creator => e.creator.email, :start_time => e.start.dateTime, :end_time => e.end.dateTime, :breaks => breaks, :job_id => j.id, :notes => e.description )      
      @record.save        
    end
    #send out consolidated emails
    send_warning_emails
    @events = Record.find(:all, :order => 'start_time')        
    
    
  end #BUILD_DATA
  
  
  
  
  def numeric?(object)
    true if Float(object) rescue false
  end  
  
  
  def calc_breaks(event_description)
    result = event_description.slice(/[Bb]reak[s]?:\s*[0-9]*/)
    if not result.nil?
      result = result.split(':').map{|x| x.strip}

      if result.length >1 and numeric?(result[1]) 
        return Float(result[1])
      else
        return -1
      end
    else
      return -1    
    end
  end


#  def download_zip(csv_list)
#    if !image_list.blank?
#      file_name = "pictures.zip"
#     t = Tempfile.new("my-temp-filename-#{Time.now}")
#      Zip::ZipOutputStream.open(t.path) do |z|
#        image_list.each do |img|
#          title = img.title
#          title += ".jpg" unless title.end_with?(".jpg")
#          z.put_next_entry(title)
#          z.print IO.read(img.path)
#        end
#      end
#      send_file t.path, :type => 'application/zip',
#                             :disposition => 'attachment',
#                             :filename => file_name
#      t.close
#    end
#    end
  def send_warning_emails
    notices = Notice.all
    user_notices = notices.group_by{|n| n.email}      
    user_notices.each do |email_to, nots|
      nots.each do |note|
        consolidated_message = note.subject + '<br/>'
        consolidated_message = note.body + '<br/>'
      end      
      ErrorMailer.timesheet_warning(email_to, consolidated_message).deliver 
    end
  end


  def send_project_csvs(project_events, file_name)    
    project_csvs = {}
    project_events.each do |project, events|
      tmp_csv = Tempfile.new("temp_csv_file-#{Time.now}")
      project_csvs[project] = tmp_csv
      CSV.open(tmp_csv, "wb") do |csv|
        csv << ['user','job','start','end','breaks']
        events.each do |e|
          csv << [ e.creator, e.job.name, e.start_time, e.end_time, e.breaks ]
        end    
        tmp_csv.write(csv)
      end         
    end
    zout = Tempfile.new("temp_zip_file-#{Time.now}")
    Zip::ZipOutputStream.open(zout.path) do |z|
      project_csvs.each do |project, pcsv|
        z.put_next_entry(project + "-#{Time.now}.csv", nil, nil, Zip::ZipEntry::DEFLATED, Zlib::BEST_COMPRESSION )
        z.print IO.read(pcsv.path)
        pcsv.close
        pcsv.unlink
      end
    end
    send_file zout.path, :type => 'application/zip', :disposition => 'attachment', :filename => file_name
    zout.close
    zout.unlink
                             
  end
  
  def send_user_csvs(user_events, file_name)    
    user_csvs = {}
    user_events.each do |creator, events|
      tmp_csv = Tempfile.new("temp_scv_file-#{Time.now}")
      user_csvs[creator] = tmp_csv
      CSV.open(tmp_csv, "wb") do |csv|
        csv << ['user','job','start','end','breaks']
        events.each do |e|
          csv << [ e.creator, e.job.name, e.start_time, e.end_time, e.breaks ]
        end    
        tmp_csv.write(csv)
      end         
    end
    zout = Tempfile.new("User_Timesheets-#{Time.now}")
    Zip::ZipOutputStream.open(zout.path) do |z|
      user_csvs.each do |creator, ucsv|
        z.put_next_entry(creator + "-#{Time.now}.csv", nil, nil, Zip::ZipEntry::DEFLATED, Zlib::BEST_COMPRESSION )
        z.print IO.read(ucsv.path)
        ucsv.close
        ucsv.unlink
      end
    end
    send_file zout.path, :type => 'application/zip', :disposition => 'attachment', :filename => file_name
    zout.close
    zout.unlink
                             
  end

  
  # GET /project_timesheets
  # GET /project_timesheets.zip
  def project_timesheets

   @data_events = @events.group_by{|r| r.job.name}
   
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @events }
      format.csv { render :layout => false }
      format.zip { send_project_csvs(@data_events, "project_timesheets-#{Time.now}.zip") }
    end        
  end #end project_timesheets
  
  # GET /user_timesheets
  # GET /user_timesheets.zip
  def user_timesheets

   @data_events = @events.group_by{|r| r.creator}
   
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @events }
      format.csv { render :layout => false }
      format.zip { send_user_csvs(@data_events, "user_timesheets-#{Time.now}.zip") }
      format.xls { 
        send_data @data_events.to_xls(:only => [:start_time, :end_time, :breaks], :prepend => [["user", @data_events.first.first]], :filename => 'test.xls')
        return 
      }
    end        
  end #end project_timesheets
  
    
  
  
  # GET /records
  # GET /records.json
  def index



   #generate report for each project
#   @project_events = @events.group_by{|r| r.job.name}
   #generate report for each user
   @user_events = @events.group_by{|r| r.creator}   

   #check each user for missing days.
   days = []
   @tMin.to_date.upto(@tMax.to_date) do |day|
     if not [0,6].include? day.wday #and not day.holiday?(:au)
      days << day
     end  
   end   
   @user_events.each do |user,events|     
     user_days = []
     events.each do |event|
       user_days << event.start_time.to_date
     end
     missed = days - user_days
     if not missed.empty?
       #this is not being queued using notices... maybe it should be
       ErrorMailer.missed_days(user, missed).deliver      
     end
   end
    
       
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @events }
      format.csv { render :layout => false }
    end
  end

#  get '/oauth2authorize' do
  def oauth2authorize
    redirect_to @client.authorization.authorization_uri(:approval_prompt => :auto).to_s, :status => 303
  end

#  get '/oauth2callback' do
  def oauth2callback
    @client.authorization.fetch_access_token!
    # Persist the token here
    token_pair = 
    if session[:token_id]
      token_pair = TokenPair.get(session[:token_id])
    else
      TokenPair.destroy_all
      token_pair = TokenPair.new
    end
    token_pair.update_token!(@client.authorization)
    token_pair.save
    session[:token_id] = token_pair.id
    redirect_to 'http://localhost:3000/home'
  end
    
    
    
    
    
    
    
    
    
    
    
    
  # GET /records/1
  # GET /records/1.json
  def show
    @record = Record.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @record }
    end
  end

  # GET /records/new
  # GET /records/new.json
  def new
    @record = Record.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @record }
    end
  end

  # GET /records/1/edit
  def edit
    @record = Record.find(params[:id])
  end

  # POST /records
  # POST /records.json
  def create
    @record = Record.new(params[:record])

    respond_to do |format|
      if @record.save
        format.html { redirect_to @record, notice: 'Record was successfully created.' }
        format.json { render json: @record, status: :created, location: @record }
      else
        format.html { render action: "new" }
        format.json { render json: @record.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /records/1
  # PUT /records/1.json
  def update
    @record = Record.find(params[:id])

    respond_to do |format|
      if @record.update_attributes(params[:record])
        format.html { redirect_to @record, notice: 'Record was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @record.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /records/1
  # DELETE /records/1.json
  def destroy
    @record = Record.find(params[:id])
    @record.destroy

    respond_to do |format|
      format.html { redirect_to records_url }
      format.json { head :no_content }
    end
  end
end
